#!/usr/bin/env python2
# -*- coding: utf-8 -*-

import json
import datetime

from sqlalchemy import text

from Ump.objs.db import models
from Ump.schedule.utils import log_info_run
from Ump.objs.session_wrapper import _sw

from Ump.objs.alert.api import AlertApi
from Ump.schedule.jobs.base import JobBase
from Ump.common import log


job_log = log.get_logger(__name__)

alert_api = AlertApi()


class AllVolumeNumberAlert(object):
    def get_current_value(self):
        volume_number = models.Volume.query.count()
        return volume_number

    def alert(self, alert_value, snmp, is_mail=True):
        current_value = self.get_current_value()
        if current_value > alert_value:
            detail = "Total volumes number is %s now, over %s" % (current_value, alert_value)
            values = {'detail': detail, 'level': 'WARNING', 'returncode': '9006'}
            alert_api.alert_create(values, is_snmp=snmp, is_mail=is_mail)


class PoolVolumeNumberAlert(object):
    def get_current_value(self):
        pool_list = models.Pool.query.all()
        result = []
        for pool in pool_list:
            pool_name = pool.name
            volume_number = _sw.query(models.Volume).\
                from_statement(text("SELECT * FROM volume WHERE pool_id=:pool_id")).\
                params(pool_id=pool.id).count()
            result.append((pool_name, volume_number))
        return result

    def alert(self, alert_value, snmp, is_mail=True):
        for item in self.get_current_value():
            if item[1] and float(item[1]) > alert_value:
                alert_name = item[0]
                current_value = item[1]
                detail = "Volume number in pool[%s] is %s now, over %s" % (alert_name, current_value, alert_value)
                values = {'detail': detail, 'level': 'WARNING', 'returncode': '9007'}
                alert_api.alert_create(values, is_snmp=snmp, is_mail=is_mail)


class DiskPercentAlert(object):
    def get_current_value(self):
        return float(models.Cluster.query.first().disk_percent)

    def alert(self, alert_value, snmp, is_mail=True):
        current_value = self.get_current_value()
        if current_value > alert_value:
            detail = "集群物理容量空间使用率超过%s%%, 当前使用率%.2f%%" % (alert_value, current_value)
            values = {'detail': detail, 'level': 'WARNING', 'returncode': '9001'}
            alert_api.alert_create(values, is_snmp=snmp, is_mail=is_mail)


class CPUPercentAlert(object):
    def get_current_value(self):
        host_list = models.Host.query.all()
        result = []
        for host in host_list:
            cpu_percent = host.usage_cpu
            if cpu_percent:
                result.append((host, cpu_percent * 100))
        return result

    def alert(self, alert_value, snmp, is_mail=True):
        for item in self.get_current_value():
            if item[1] and float(item[1]) > alert_value:
                host = item[0]
                if not host.cpu_alert:
                    current_value = item[1]
                    detail = "CPU usage of host[%s] is %.2f%% now, over %s%%" % (host.name, current_value, alert_value)
                    values = {'detail': detail, 'position': host.ip, 'level': 'WARNING', 'returncode': '9008'}
                    alert_api.alert_create(values, is_snmp=snmp, is_mail=is_mail)
                    host.update({'cpu_alert': True})
            else:
                host = item[0]
                host.update({'cpu_alert': False})


class MemoryPercentAlert(object):
    def get_current_value(self):
        host_list = models.Host.query.all()
        result = []
        for host in host_list:
            memory_percent = host.usage_mem
            if memory_percent:
                result.append((host, memory_percent * 100))
        return result

    def alert(self, alert_value, snmp, is_mail=True):
        for item in self.get_current_value():
            if item[1] and float(item[1]) > alert_value:
                host = item[0]
                if not host.memory_alert:
                    current_value = item[1]
                    detail = "Memory usage of host[%s] is %.2f%% now, over %s%%" % (host.name, current_value, alert_value)
                    values = {'detail': detail, 'position': host.ip, 'level': 'WARNING', 'returncode': '9010'}
                    alert_api.alert_create(values, is_snmp=snmp, is_mail=is_mail)
                    host.update({'memory_alert': True})
            else:
                host = item[0]
                host.update({'memory_alert': False})


class NetworkPercentAlert(object):
    def get_current_value(self):
        host_list = models.Host.query.all()
        result = []
        for host in host_list:
            if host.iops_str:
                network_percent = json.loads(host.iops_str).get('_speed')
                result.append((host, network_percent))
        return result

    def alert(self, alert_value, snmp, is_mail=True):
        for item in self.get_current_value():
            if item[1] and float(item[1]) > alert_value:
                host = item[0]
                current_value = item[1]
                detail = "Network bandwidth usage of host[%s] is %s MB now, over %s MB" % (host.name, current_value, alert_value)
                values = {'detail': detail, 'position': host.ip, 'level': 'WARNING', 'returncode': '9011'}
                alert_api.alert_create(values, is_snmp=snmp, is_mail=is_mail)


class LatencyAlert(object):

    def get_current_value(self):
        latency = models.Latency.query.get(1)
        read_latency_val = latency.read_latency_val
        write_latency_val = latency.write_latency_val
        ret_val = None
        if read_latency_val and write_latency_val:
            if read_latency_val > write_latency_val:
                ret_val = write_latency_val
            else:
                ret_val = read_latency_val
        elif read_latency_val and not write_latency_val:
            ret_val = read_latency_val
        elif write_latency_val and not read_latency_val:
            ret_val = write_latency_val
        return ret_val

    def alert(self, alert_value, snmp, is_mail=True):
        current_value = self.get_current_value()
        if current_value and int(current_value) > alert_value:
            detail = "Latency is %s μs now, over %s μs" % (current_value, alert_value)
            values = {'detail': detail, 'level': 'WARNING', 'returncode': '9012'}
            alert_api.alert_create(values, is_snmp=snmp, is_mail=is_mail)


class AlertJob(JobBase):
    job_items = {
        'disk_capacity': DiskPercentAlert(),
        'volume_number': AllVolumeNumberAlert(),
        'pool_volume_number': PoolVolumeNumberAlert(),
        'memory_usage': MemoryPercentAlert(),
        'CPU_usage': CPUPercentAlert(),
        'network_bandwidth': NetworkPercentAlert(),
        'latency': LatencyAlert(),
    }

    def __init__(self, alert=True, snmp=True):
        self.alert = alert
        self.snmp = snmp
        super(AlertJob, self).__init__()

    @log_info_run()
    def run(self, context):
        job_name = context.get('job_name')
        job_log.info('%s! The time is: %s' % (job_name, datetime.datetime.now()))

        config = models.SysconfigForUMP.query.filter_by(**{'name': '%s.threshold' % job_name}).first()
        if config:
            alert_value = int(config.value_setting)

            job_event = self.job_items.get(job_name)
            job_event.alert(alert_value, self.snmp)


class LichSyslogMonitor(JobBase):

    @log_info_run()
    def run(self, context):
        self.monitorm.monitor_main()


if __name__ == "__main__":
    job = AlertJob()
    job.run('')
